package simulation;

import itecs.Itecs;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;

import org.cloudbus.cloudsim.distributions.UniformDistr;

import util.Globals;
import models.SLA;

public class SimulationController {

	static double lambda1 = 0;
	static double lambda2 = 0;
	static SLA sla1 = null;
	static SLA sla2 = null;

	static int errors = 0;

	private static ArrayList<ArrayList<Double>> throughputObservation = new ArrayList<ArrayList<Double>>();
	private static ArrayList<ArrayList<Double>> responseObservation = new ArrayList<ArrayList<Double>>();
	private static ArrayList<ArrayList<Double>> queueLenObservation = new ArrayList<ArrayList<Double>>();
	private static ArrayList<ArrayList<Double>> utilizationObservation = new ArrayList<ArrayList<Double>>();
	private static ArrayList<ArrayList<Double>> instantUtilizationObservation = new ArrayList<ArrayList<Double>>();

	private static ArrayList<Double> throughputObservationMeans = new ArrayList<Double>();
	private static ArrayList<Double> responseObservationMeans = new ArrayList<Double>();
	private static ArrayList<Double> queueLenObservationMeans = new ArrayList<Double>();
	private static ArrayList<Double> utilizationObservationMeans = new ArrayList<Double>();
	private static ArrayList<Double> instantUtilizationObservationMeans = new ArrayList<Double>();

	private static ArrayList<Double> responseObservationVar = new ArrayList<Double>();
	private static ArrayList<Double> queueLenObservationVar = new ArrayList<Double>();
	private static ArrayList<Double> throughputObservationVar = new ArrayList<Double>();
	private static ArrayList<Double> utilizationObservationVar = new ArrayList<Double>();
	private static ArrayList<Double> instantUtilizationObservationVar = new ArrayList<Double>();



	private static ArrayList<Integer> ms;
	private static ArrayList<Integer> stabs;

	/*
	 * calculates the stabilization campionary mean and prints it on a *.csv
	 * file USES getReplicatedRunsStabilizationMeans which calculates the means
	 * over single runs
	 */
	private static void writeReplicatedRunsCampionaryMean(String brokerType,
			String serviceType) throws IOException {

		System.out.println("Calculating RR Means..");

		queueLenObservationMeans = getReplicatedRunsStabilizationMeans(queueLenObservation);
		responseObservationMeans = getReplicatedRunsStabilizationMeans(responseObservation);
		throughputObservationMeans = getReplicatedRunsStabilizationMeans(throughputObservation);
		utilizationObservationMeans = getReplicatedRunsStabilizationMeans(utilizationObservation);
		instantUtilizationObservationMeans = getReplicatedRunsStabilizationMeans(instantUtilizationObservation);

		FileWriter file = new FileWriter("output/rr" + brokerType + "-"
				+ lambda1 + "-" + lambda2 + "-" + serviceType + "-" + sla1
				+ "-" + sla2 + "means.csv", false);
		file
		.write("Sample size \t Queue len \t Response time \t Throughput \t Instant Utilization \t Utilization \n");

		DecimalFormat dft = new DecimalFormat("##0.00");

		for (int i = 0; i < queueLenObservationMeans.size(); i++) {
			file.write((i + 1) + "\t"
					+ dft.format(queueLenObservationMeans.get(i)) + "\t"
					+ dft.format(responseObservationMeans.get(i)) + "\t"
					+ dft.format(throughputObservationMeans.get(0)) + "\t"
					+ dft.format(instantUtilizationObservationMeans.get(i))
					+ "\t" + dft.format(utilizationObservationMeans.get(0))
					+ "\n");
		}

		file.flush();
		file.close();

		System.out.println("RR Means Calculated!");
	}

	/*
	 * calculates the stabilization campionary variance and prints it on a *.csv
	 * file USES getReplicatedRunsStabilizationMeans which calculates the means
	 * over single runs
	 */
	private static void writeReplicatedRunsCampionaryVariance(
			String brokerType, String serviceType) throws IOException {

		System.out.println("Calculating RR Variances..");

		ArrayList<Double> queueLenArr = queueLenObservationMeans;
		ArrayList<Double> responseArr = responseObservationMeans;
		ArrayList<Double> throughputArr = throughputObservationMeans;
		ArrayList<Double> utilizationArr = utilizationObservationMeans;
		ArrayList<Double> instantUtilizationArr = instantUtilizationObservationMeans;

		responseObservationVar.clear();
		queueLenObservationVar.clear();
		throughputObservationVar.clear();
		utilizationObservationVar.clear();
		instantUtilizationObservationVar.clear();

		for (int v = 1; v <= responseObservation.get(0).size(); v++) {

			double total = 0;
			double respVar = 0;
			double queueVar = 0;
			double thrVar = 0;
			double utVar = 0;
			double iutVar = 0;

			for (int j = 0; j < responseObservation.size(); j++) {

				double responseMean = 0;
				double responseSum = 0;
				double queueMean = 0;
				double queueSum = 0;
				double thrMean = 0;
				double thrSum = 0;
				double utMean = 0;
				double utSum = 0;
				double iutMean = 0;
				double iutSum = 0;
				total = 0;

				for (int i = 0; i < v - 1; i++) {
					responseSum += responseObservation.get(j).get(i);
					queueSum += queueLenObservation.get(j).get(i);
					iutSum += instantUtilizationObservation.get(j).get(i);
					thrSum += throughputObservation.get(j).get(0);
					utSum += utilizationObservation.get(j).get(0);
					total++;
				}

				if (v == 1) {
					responseSum += responseObservation.get(j).get(0);
					queueSum += queueLenObservation.get(j).get(0);
					iutSum += instantUtilizationObservation.get(j).get(0);
					thrSum += throughputObservation.get(j).get(0);
					utSum += utilizationObservation.get(j).get(0);
					total++;
				}

				responseMean = responseSum / total;
				queueMean = queueSum / total;
				thrMean = thrSum / total;
				utMean = utMean / total;
				iutMean = iutMean / total;

				respVar += (Math.pow(responseMean
						- responseArr.get((int) total - 1), 2) / (responseObservation
								.size() - 1))
								/ Math.sqrt(total);
				queueVar += (Math.pow(queueMean
						- queueLenArr.get((int) total - 1), 2) / (queueLenObservation
								.size() - 1))
								/ Math.sqrt(total);
				iutVar += (Math.pow(iutMean
						- instantUtilizationArr.get((int) total - 1), 2) / (instantUtilizationObservation
								.size() - 1))
								/ Math.sqrt(total);
				thrVar += (Math.pow(thrMean - throughputArr.get(0), 2) / (throughputObservation
						.size() - 1))
						/ Math.sqrt(total);
				utVar += (Math.pow(utMean - utilizationArr.get(0), 2) / (utilizationObservation
						.size() - 1))
						/ Math.sqrt(total);
			}

			responseObservationVar
			.add((respVar / (responseObservation.size() - 1))
					/ total);
			queueLenObservationVar
			.add((queueVar / (queueLenObservation.size() - 1))
					/ total);
			throughputObservationVar.add((thrVar / (throughputObservation
					.size() - 1))
					/ total);
			utilizationObservationVar.add((utVar / (utilizationObservation
					.size() - 1))
					/ total);
			instantUtilizationObservationVar
			.add((iutVar / (instantUtilizationObservation.size() - 1))
					/ total);
		}

		FileWriter file = new FileWriter("output/rr" + brokerType + "-"
				+ lambda1 + "-" + lambda2 + "-" + serviceType + "-" + sla1
				+ "-" + sla2 + "variances.csv", false);
		file
		.write("Sample Size \t Queue len V \t Response time V \t Throughput V \t Instant Utilization V \t Utilization V \n");

		DecimalFormat dft = new DecimalFormat("##0.0000");

		for (int i = 0; i < responseObservationVar.size(); i++) {
			file.write(((i + 1)) + "\t"
					+ dft.format(queueLenObservationVar.get(i)) + "\t"
					+ dft.format(responseObservationVar.get(i)) + "\t"
					+ dft.format(throughputObservationVar.get(i)) + "\t"
					+ dft.format(instantUtilizationObservationVar.get(i))
					+ "\t" + dft.format(utilizationObservationVar.get(i))
					+ "\n");
		}

		file.flush();
		file.close();

		System.out.println("RR Variances Calculated!");
	}

	// calculates the n means for n runs of a replicated runs simulation
	private static ArrayList<Double> getReplicatedRunsStabilizationMeans(
			ArrayList<ArrayList<Double>> observation) {

		ArrayList<Double> resultMeans = new ArrayList<Double>();

		int minSize = Integer.MAX_VALUE;

		for (int j = 0; j < observation.size(); j++) {
			if (minSize > observation.get(j).size())
				minSize = observation.get(j).size();
		}

		for (int v = 1; v <= minSize; v++) {

			double total = 0;
			double outerSum = 0;

			for (int j = 0; j < observation.size(); j++) {

				double mean = 0;
				double sum = 0;
				total = 0;

				for (int i = 0; i < v; i++) {
					sum += observation.get(j).get(i);
					total++;
				}

				if (v == 1) {
					sum += observation.get(j).get(0);
					total++;
				}

				mean = sum / total;
				outerSum += mean;
			}
			resultMeans.add(outerSum / observation.size());

		}

		return resultMeans;
	}

	/*
	 * n run -> n medie sui run n medie sui run -> media delle medie sui run n
	 * medie sui run + media delle medie sui run -> varianza delle medie sui run
	 */
	private static double[] getMeanAndConfidenceReplicatedRun(
			ArrayList<ArrayList<Double>> observation) {

		int size = observation.get(0).size();

		for (int j = 0; j < observation.size(); j++) {
			if (size > observation.get(j).size())
				size = observation.get(j).size();
		}

		double meanSum = 0;
		double sumVar = 0;
		double the_variance = 0;
		ArrayList<Double> rowMeanObservations = new ArrayList<Double>();

		int start = Globals.SIMULATION_STABILIZATION_CLOUDLETS;
		if (size == 1)
			start = 0;

		for (int j = 0; j < observation.size(); j++) {

			double sum = 0;

			for (int i = start; i < size; i++) {
				sum += observation.get(j).get(i);
			}

			meanSum += sum / (size - start);
			rowMeanObservations.add(sum / (size - start));
		}

		double the_mean = meanSum / observation.size();

		for (int j = 0; j < rowMeanObservations.size(); j++) {
			sumVar += Math.pow(rowMeanObservations.get(j) - the_mean, 2);
		}

		the_variance = sumVar / (rowMeanObservations.size() - 1);

		double dt = Globals.U_95_PERCENT
		* (Math.sqrt(the_variance) / Math.sqrt(rowMeanObservations
				.size()));

		double[] res = new double[3];
		res[0] = the_mean;
		res[1] = the_mean - dt;
		res[2] = the_mean + dt;


		System.out.println("Observed Mean: " + res[0]);
		System.out.println("95% Confidence Interval: [" + res[1] + ", "
				+ res[2] + "]");
		System.out.println("Confidence Interval size : " + (res[2] - res[1]));

		return res;
	}

	public static void clearObservations() {
		throughputObservation.clear();
		responseObservation.clear();
		queueLenObservation.clear();
		utilizationObservation.clear();
		instantUtilizationObservation.clear();
	}

	/*
	 * gets the observation ArrayList and splits it in type separated
	 * observations
	 */
	public static void splitObservations(ArrayList<Observation> obs, double th,
			double U) {

		ArrayList<Double> respT = new ArrayList<Double>();
		ArrayList<Double> queueL = new ArrayList<Double>();
		ArrayList<Double> throughP = new ArrayList<Double>();
		ArrayList<Double> utilizations = new ArrayList<Double>();
		ArrayList<Double> instantUtilizations = new ArrayList<Double>();

		int cloudletLimit = Globals.SIMULATION_STABILIZATION_CLOUDLETS
		+ Globals.SIMULATION_CLOUDLETS;

		if (obs.size() < cloudletLimit) {
			System.err.println("ERROR: not enough observations!!!!!");
			cloudletLimit = obs.size();
			// System.exit(-1);
			errors++;
		}

		for (int j = 0; j < cloudletLimit; j++) {
			respT.add(obs.get(j).getResponseTime());
			queueL.add(obs.get(j).getQueueLen());
			instantUtilizations.add(obs.get(j).getIU());
		}

		throughP.add(th);
		utilizations.add(U);

		responseObservation.add(respT);
		queueLenObservation.add(queueL);
		instantUtilizationObservation.add(instantUtilizations);
		throughputObservation.add(throughP);
		utilizationObservation.add(utilizations);
	}


	public static void getMAndStabFromFile(){

		int m, stab;
		BufferedReader bufferedReader = null;
		ms = new ArrayList<Integer>();
		stabs = new ArrayList<Integer>();

		String line = null;
		String[] tokens = null;


		try {
			bufferedReader = new BufferedReader(new FileReader("mAndStab.csv"));
			while ((line = bufferedReader.readLine()) != null) {
				tokens = line.split("\t");
				m=Integer.parseInt(tokens[0]);
				stab=Integer.parseInt(tokens[1]);
				ms.add(m);
				stabs.add(stab);
				//System.out.println(m + "---" + stab );
			}
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}catch (IOException e1) {
			e1.printStackTrace();
		}



	}

	private static int getStabilizationTime() {
		// calcola la media campionaria
		double partialMean = 0;
		double previousMean = 0;
		double variance = 0;
		double previousVariance = 0;
		double STABLE_SYSTEM_TRESHOLD = 1000;
		int j = 0;
		for (int i = 0; i < responseObservationMeans.size(); i++) {

			partialMean = responseObservationMeans.get(i);
			variance = responseObservationVar.get(i);

			// System.out.println("Variance:" + variance);

			if (Math.abs(partialMean - previousMean) <= 0.04
					&& Math.abs(variance - previousVariance) <= 0.01) {
				// System.out.println("Ora provo a stabilizzarmi qui: " + i);
				// System.out.println("Diff:" + Math.abs(partialMean -
				// previousMean));
				// System.out.println("Diff var: " + Math.abs(variance -
				// previousVariance));
				previousMean = partialMean;
				previousVariance = variance;
				for (j = i + 1; j <= i + STABLE_SYSTEM_TRESHOLD; j++) {
					if (j >= responseObservationMeans.size()) {
						System.out.println("SISTEMA NON STABILE A:" + j + "\n");
						return -1;
					}
					partialMean = responseObservationMeans.get(j);
					variance = responseObservationVar.get(j);

					if (Math.abs(partialMean - previousMean) >= 0.04
							|| Math.abs(variance - previousVariance) >= 0.01) {
						// System.out.println(j + ") NON SE STABILIZZA!");
						break;
					}
					if (j == STABLE_SYSTEM_TRESHOLD + i - 1) {
						System.out.println("SISTEMA STABILE A:" + j + "\n");
						return j;
					}
				}

			}

			previousMean = responseObservationMeans.get(i);
			previousVariance = responseObservationVar.get(i);
		}
		System.out.println("SISTEMA NON STABILE A:" + j + "\n");
		return -1;

	}

	public static void finalStab() {

		FileWriter file;
		try {
			file = new FileWriter("output/eval.csv", true);
			file
			.write("lambda1 \t lambda2 \t traffic type \t sla1 \t sla2  \t mu \t FCFS-DA m1 \t FCFS-DA m2 \t FCFS-DA tot \t FCFS-SA \t HOL \t PDP\n");
			file.flush();
			file.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		ArrayList<ArrayList<Integer>> strategiesEval = new ArrayList<ArrayList<Integer>>();

		int start = 5;
		int end = 20;
		int jump = 5;

		String[] serviceDistributions = { "PARETO", "EXP" };

		for (int t = 0; t < serviceDistributions.length; t++) {
			String serviceDistribution = serviceDistributions[t];

			for (int g = 0; g < Globals.GSLAS.length; g++) {

				sla1 = Globals.GSLAS[g][0].getSla();
				sla2 = Globals.GSLAS[g][1].getSla();

				for (int l1 = start; l1 < end; l1 += jump) {
					for (int l2 = start; l2 < end; l2 += jump) {

						if (l1 + l2 > end)
							continue;

						try {

							file = new FileWriter("output/evalstab.csv", true);
							file.write("brokerType" + "\t" + "trafficType"
									+ "\t" + "lambda1" + "\t" + "lambda2"
									+ "\t" + "sla1" + "\t" + "sla2" + "\t"
									+ "numberOfServers" + "\t"
									+ "stabilization" + "\n");
							file.flush();
							file.close();

							file = new FileWriter("output/stabilization.csv",
									true);
							file
							.write("lambda1 \t lambda2 \t sla1 \t sla2 \t broker \t traffic type \t stabilization cloudlets\n");
							file.flush();
							file.close();
						} catch (IOException e) {
							e.printStackTrace();
						}

						System.gc();

						if (serviceDistribution.equals("EXP"))
							Globals.SIMULATION_TIME = 2.5
							* (Globals.SIMULATION_STABILIZATION_CLOUDLETS + Globals.SIMULATION_CLOUDLETS)
							/ (l1 + l2);
						else
							Globals.SIMULATION_TIME = 5
							* (Globals.SIMULATION_STABILIZATION_CLOUDLETS + Globals.SIMULATION_CLOUDLETS)
							/ (l1 + l2);

						System.out.println("Heuristic simulation time: "
								+ Globals.SIMULATION_TIME);
						System.out.println();
						System.out.println();

						lambda1 = l1;
						lambda2 = l2;

						String brokerType = null;

						// FCFS, HOL, PDP shared allocation
						String[] brokerTypes = { "FCFS", "HOL", "PDP" };
						int[] numberOfSharedServers = { 0, 0, 0 };

						for (int b = 0; b < brokerTypes.length; b++) {

							brokerType = brokerTypes[b];
							clearObservations();

							try {
								numberOfSharedServers[b] = Itecs.getOptimalM(
										brokerType, sla1, sla2, lambda1,
										lambda2, serviceDistribution);

								if (numberOfSharedServers[b] == -1) {
									System.out
									.println("Impossibile rispettare gli SLA con questi parametri.");
									System.exit(-1);
								}

								Itecs itecs = new Itecs(brokerType, sla1, sla2,
										"EXP", lambda1, lambda2);

								for (int i = 0; i < Globals.SEEDS.length; i++) {
									itecs.startWithParams(Globals.SEEDS[i],
											numberOfSharedServers[b]);
									itecs.printStats();
									System.out.println(brokerType
											+ " obs size: "
											+ itecs.getObservations().size());
									splitObservations(itecs.getObservations(),
											itecs.getRunThroughput(), itecs
											.getUtilization());
								}

								if (Globals.STABILIZATION_ONLY) {
									writeReplicatedRunsCampionaryMean(
											brokerType, serviceDistribution);
									writeReplicatedRunsCampionaryVariance(
											brokerType, serviceDistribution);

									int stabilization = getStabilizationTime();

									try {
										file = new FileWriter(
												"output/evalstab.csv", true);
										file.write(brokerType + "\t"
												+ serviceDistribution + "\t"
												+ lambda1 + "\t" + lambda2
												+ "\t" + sla1 + "\t" + sla2
												+ "\t"
												+ numberOfSharedServers[b]
												                        + "\t" + stabilization + "\n");
										file.flush();
										file.close();

										file = new FileWriter(
												"output/stabilization.csv",
												true);
										file.write(lambda1 + "\t" + lambda2
												+ "\t" + sla1 + "\t" + sla2
												+ "\t" + brokerType + "\t"
												+ serviceDistribution + "\t"
												+ stabilization + "\n");
										file.flush();
										file.close();
									} catch (IOException e) {
										e.printStackTrace();
									}
									;
								}

								if (Globals.OBSERVATION_STUDY_ONLY) {

									System.out
									.println("\nMean and confidence intervals for RESPONSE TIME");
									getMeanAndConfidenceReplicatedRun(responseObservation);

									System.out
									.println("\nMean and confidence intervals for QUEUE LENGTH");
									getMeanAndConfidenceReplicatedRun(queueLenObservation);

									System.out
									.println("\nMean and confidence intervals for THROUGHPUT");
									getMeanAndConfidenceReplicatedRun(throughputObservation);

									System.out
									.println("\nMean and confidence intervals for INSTANT UTILIZATION");
									getMeanAndConfidenceReplicatedRun(instantUtilizationObservation);

									System.out
									.println("\nMean and confidence intervals for UTILIZATION");
									getMeanAndConfidenceReplicatedRun(utilizationObservation);
								}

							} catch (Exception e) {
								e.printStackTrace();
							}
						}

						try {
							file = new FileWriter("output/eval.csv", true);
							file.write(lambda1
									+ "\t"
									+ lambda2
									+ "\t"
									+ serviceDistribution
									+ "\t"
									+ sla1
									+ "\t"
									+ sla2
									+ "\t"
									+ (1 / Globals.CLOUDLET_LENGTH_MEAN)
									/ Globals.VM_MIPS + "\t"
									+ numberOfSharedServers[0] + "\t"
									+ numberOfSharedServers[1] + "\t"
									+ numberOfSharedServers[2] + "\n");
							file.flush();
							file.close();

							System.out.println("FCFS: "
									+ numberOfSharedServers[0] + "\nHOL: "
									+ numberOfSharedServers[1] + "\nPDP: "
									+ numberOfSharedServers[2]);

							ArrayList<Integer> singleIterationMs = new ArrayList<Integer>();
							singleIterationMs.add(numberOfSharedServers[0]);
							singleIterationMs.add(numberOfSharedServers[1]);
							singleIterationMs.add(numberOfSharedServers[2]);

							strategiesEval.add(singleIterationMs);
							System.err.println("ERRORS: " + errors);

						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}

		// optimality evaluation wrt fraction of times
		// in which a strategy needs the minimal number of servers
		// to met the SLAs
		double[] eval = { 0, 0, 0, 0 };

		for (int i = 0; i < strategiesEval.size(); i++) {

			int min = Integer.MAX_VALUE;

			for (int j = 0; j < strategiesEval.get(i).size(); j++) {
				if (min > strategiesEval.get(i).get(j))
					min = strategiesEval.get(i).get(j);
			}

			for (int j = 0; j < strategiesEval.get(i).size(); j++) {
				if (min == strategiesEval.get(i).get(j))
					eval[j]++;
			}

		}

		System.out.println();
		System.out.println("FCFS-s: " + (eval[1] / strategiesEval.size()) * 100	+ " %");
		System.out.println("HOL: " + (eval[2] / strategiesEval.size()) * 100 + " %");
		System.out.println("PDP: " + (eval[3] / strategiesEval.size()) * 100 + " %");
		System.out.println();
		System.err.println("ERRORS: " + errors);

	}







	public static void finalM() {

		try {
			double lower = 3;
			double upper = 8;
			int gSlaCouples = 30;

			UniformDistr ud1=new UniformDistr(lower, upper, Globals.SEEDS[0]);
			UniformDistr ud2=new UniformDistr(lower, upper, Globals.SEEDS[1]);

			double x1 = ud1.sample();
			double x2 = ud2.sample();

			double yarray[] = { 0.80, 0.85, 0.90, 0.95 };
			double y1 = yarray[(int) (ud1.sample() % yarray.length)];
			double y2 = yarray[(int) (ud2.sample() % yarray.length)];

			String[] serviceDistributions = { "PARETO", "EXP" };
			String[] brokerTypes = { "FCFS", "HOL", "PDP" };

			int ms[] = new int[brokerTypes.length];

			int lambdaStart = 5;
			int lambdaEnd = 20;
			int lambdaJump = 5;

			int totalrun = 0;
			int confcounter = 0;
			int confScore[] = new int[brokerTypes.length];
			SLA slas[][] = new SLA[2][gSlaCouples];

			String serviceDistribution = null;

			FileWriter f = new FileWriter("output/ms.csv", false);
			f.write("Service \t SLA1 \t SLA2 \t l1 \t l2 \t FCFS \t HOL \t PDP \n");

			for (int i = 0; i < gSlaCouples; i++) {
				x1 = ud1.sample();
				y1 = yarray[(int) (ud1.sample() % yarray.length)];
				x2 = ud2.sample();
				y2 = yarray[(int) (ud2.sample()%yarray.length)];
				SLA sla1 = new SLA(x1, y1);
				SLA sla2 = new SLA(x2, y2);
				slas[0][i] = sla1;
				slas[1][i] = sla2;
			}



			for (int i = 20; i < 30; i++) {

				sla1=slas[0][i];
				sla2=slas[1][i];

				for (int j = 0; j < serviceDistributions.length; j++) {

					serviceDistribution = serviceDistributions[j];

					for (int l1 = lambdaStart; l1 < lambdaEnd; l1 += lambdaJump) {
						for (int l2 = lambdaStart; l2 < lambdaEnd; l2 += lambdaJump) {
							if (l1 + l2 > lambdaEnd)
								continue;

							int minScore = Integer.MAX_VALUE;


							for (int b = 0; b < brokerTypes.length; b++) {

								String type = brokerTypes[b];


								ms[b] = Itecs.getOptimalM(type, sla1, sla2, l1, l2, serviceDistribution);
								if (minScore > ms[b]) {
									minScore = ms[b];
								}
								totalrun++;




							}
							confcounter++;
							f.write(serviceDistribution + "\t" + sla1 + "\t" + sla2 + "\t" + l1 + "\t" + l2 + "\t");
							for (int e=0; e<ms.length; e++){
								f.write(ms[e] + "\t");
							}
							f.write("\n");
							f.flush();
							for (int k = 0; k < ms.length; k++) {
								if (ms[k] == minScore) {
									confScore[k]++;
								}
							}
						}

					}
					FileWriter f2 = new FileWriter("output/scores.csv", true);
					f2.write(serviceDistribution + "\t");

					for (int e = 0; e < confScore.length; e++) {
						f2.write((((double)confScore[e] /(double) confcounter)*100) + "\t");
					}
					f2.write("\n");
					f2.flush();
					f2.close();

				}


			}
		} catch (IOException e1) {
			e1.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void finalMeans(){

		getMAndStabFromFile();
		int confCounter=0;
		int start = 5;
		int end = 20;
		int jump = 5;

		FileWriter f;
		try {
			f = new FileWriter("output/results.csv", false);

			f.write("Service \t Broker \t l1 \t l2 \t R \t R+ \t R- \t Q \t Q+ \t Q- \t T \t Ui \t U+ \t U- \t U \n");
			f.flush();

			String[] serviceDistributions = { "PARETO", "EXP" };

			for (int t = 0; t < serviceDistributions.length; t++) {
				String serviceDistribution = serviceDistributions[t];

				for (int g = 0; g < Globals.GSLAS.length; g++) {

					sla1 = Globals.GSLAS[g][0].getSla();
					sla2 = Globals.GSLAS[g][1].getSla();

					for (int l1 = start; l1 < end; l1 += jump) {
						for (int l2 = start; l2 < end; l2 += jump) {

							if (l1 + l2 > end)
								continue;

							if (serviceDistribution.equals("EXP"))
								Globals.SIMULATION_TIME = 2.5* (Globals.SIMULATION_STABILIZATION_CLOUDLETS + Globals.SIMULATION_CLOUDLETS)/ (l1 + l2);
							else
								Globals.SIMULATION_TIME = 5	* (Globals.SIMULATION_STABILIZATION_CLOUDLETS + Globals.SIMULATION_CLOUDLETS)/ (l1 + l2);

							System.out.println("Heuristic simulation time: "+ Globals.SIMULATION_TIME);
							System.out.println();
							System.out.println();

							lambda1 = l1;
							lambda2 = l2;

							String brokerType = null;

							// FCFS, HOL, PDP shared allocation
							String[] brokerTypes = { "FCFS", "HOL", "PDP" };

							for (int b = 0; b < brokerTypes.length; b++) {

								brokerType = brokerTypes[b];
								clearObservations();
								int m=ms.get(confCounter);
								Globals.SIMULATION_STABILIZATION_CLOUDLETS=stabs.get(confCounter);
								confCounter++;
								Itecs itecs=new Itecs(brokerType, sla1,sla2, serviceDistribution, l1, l2);
								for (int i = 0; i < Globals.SEEDS.length; i++) {
									itecs.startWithParams(Globals.SEEDS[i],m);
									itecs.printStats();
									System.out.println(brokerType+ " obs size: "+ itecs.getObservations().size());
									splitObservations(itecs.getObservations(),itecs.getRunThroughput(), itecs.getUtilization());
								}
								f.write(serviceDistribution + "\t" + brokerType + "\t" + l1 +"\t" + l2 + "\t" );
								System.out.println("\nMean and confidence intervals for RESPONSE TIME");
								double[] result;
								result = getMeanAndConfidenceReplicatedRun(responseObservation);
								f.write(result[0]+"\t" + result[1]+"\t" + result[2] + "\t");

								System.out.println("\nMean and confidence intervals for QUEUE LENGTH");
								result =getMeanAndConfidenceReplicatedRun(queueLenObservation);
								f.write(result[0]+"\t" + result[1]+"\t" + result[2] + "\t");

								System.out.println("\nMean and confidence intervals for THROUGHPUT");
								result =getMeanAndConfidenceReplicatedRun(throughputObservation);
								f.write(result[0]+"\t");

								System.out.println("\nMean and confidence intervals for INSTANT UTILIZATION");
								result =getMeanAndConfidenceReplicatedRun(instantUtilizationObservation);
								f.write(result[0]+"\t" + result[1]+"\t" + result[2]+ "\t");

								System.out.println("\nMean and confidence intervals for UTILIZATION");
								result = getMeanAndConfidenceReplicatedRun(utilizationObservation);
								f.write(result[0] + "\t" );
								f.write("\n");
								f.flush();
							}
						}

					}


				}
			}
			f.close();

		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}







	public static void main(String args[]) {
		
		SimulationController.finalM();
		SimulationController.finalStab();
		SimulationController.finalMeans();


	}

}